// -*- mode:c++ -*-

// Copyright (c) 2009 The University of Edinburgh
// Copyright (c) 2021 IBM Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

////////////////////////////////////////////////////////////////////
//
// The actual Power ISA decoder
// ------------------------------
//
// Power ISA v3.0B has been used for instruction formats, opcode numbers,
// opcode field names, register names, etc.
//
decode PO default Unknown::unknown() {

    format IntImmTrapOp {
        2: tdi({{ Ra }});
        3: twi({{ Ra_sw }});
    }

    4: decode VA_XO {

        // Arithmetic instructions that use source registers Ra, Rb and Rc,
        // with destination register Rt.
        format IntArithOp {
            48: maddhd({{
                int64_t res;
                std::tie(std::ignore, res) = multiplyAdd(Ra_sd, Rb_sd, Rc_sd);
                Rt = res;
            }});

            49: maddhdu({{
                uint64_t res;
                std::tie(std::ignore, res) = multiplyAdd(Ra, Rb, Rc);
                Rt = res;
            }});

            51: maddld({{
                uint64_t res;
                std::tie(res, std::ignore) = multiplyAdd(Ra_sd, Rb_sd, Rc_sd);
                Rt = res;
            }});
        }
    }

    format IntImmArithOp {
        7: mulli({{
            int64_t res = Ra_sd * si;
            Rt = res;
        }});

        8: subfic({{
            uint64_t src = ~Ra;
            Rt = src + si + 1;
        }}, true);
    }

    10: IntImmCompLogicOp::cmpli({{
        if (l)
            cr = makeCRFieldUnsigned(Ra, ui, xer.so);
        else
            cr = makeCRFieldUnsigned((uint32_t) Ra, ui, xer.so);
    }});

    11: IntImmCompOp::cmpi({{
        if (l)
            cr = makeCRFieldSigned(Ra, si, xer.so);
        else
            cr = makeCRFieldSigned((int32_t) Ra, si, xer.so);
    }});

    format IntImmArithOp {
        12: addic({{
            uint64_t src = Ra;
            Rt = src + si;
        }}, true);

        13: addic_({{
            uint64_t src = Ra;
            Rt = src + si;
        }}, true, true);
    }

    format IntImmArithCheckRaOp {
        14: addi({{ Rt = Ra + si; }},
                 {{ Rt = si }});

        15: addis({{ Rt = Ra + (si << 16); }},
                  {{ Rt = si << 16; }});
    }

    // Conditionally branch to a PC-relative or absoulute address based
    // on CR and CTR.
    16: BranchDispCondOp::bc({{ NIA = CIA + bd; }},
                             {{ NIA = bd; }});

    17: IntOp::sc({{ return std::make_shared<SESyscallFault>(); }});

    // Unconditionally branch to a PC-relative or absoulute address.
    18: BranchOp::b({{ NIA = CIA + li; }},
                    {{ NIA = li; }});

    19: decode XL_XO {

        0: CondMoveOp::mcrf({{
            uint32_t crBfa = bits(CR, 31 - bfa*4, 28 - bfa*4);
            CR = insertBits(CR, 31 - bf*4, 28 - bf*4, crBfa);
        }});

        // Conditionally branch to address in LR based on CR and CTR.
        16: BranchRegCondOp::bclr({{ NIA = LR & -4ULL; }}, true, [ IsReturn ]);

        format CondLogicOp {
            33: crnor({{
                uint32_t crBa = bits(CR, 31 - ba);
                uint32_t crBb = bits(CR, 31 - bb);
                CR = insertBits(CR, 31 - bt, !(crBa | crBb));
            }});

            129: crandc({{
                uint32_t crBa = bits(CR, 31 - ba);
                uint32_t crBb = bits(CR, 31 - bb);
                CR = insertBits(CR, 31 - bt, crBa & !crBb);
            }});
        }

        150: MiscOp::isync({{ }}, [ IsSerializeAfter ]);

        format CondLogicOp {
            193: crxor({{
                uint32_t crBa = bits(CR, 31 - ba);
                uint32_t crBb = bits(CR, 31 - bb);
                CR = insertBits(CR, 31 - bt, crBa ^ crBb);
            }});

            255: crnand({{
                uint32_t crBa = bits(CR, 31 - ba);
                uint32_t crBb = bits(CR, 31 - bb);
                CR = insertBits(CR, 31 - bt, !(crBa & crBb));
            }});

            257: crand({{
                uint32_t crBa = bits(CR, 31 - ba);
                uint32_t crBb = bits(CR, 31 - bb);
                CR = insertBits(CR, 31 - bt, crBa & crBb);
            }});

            289: creqv({{
                uint32_t crBa = bits(CR, 31 - ba);
                uint32_t crBb = bits(CR, 31 - bb);
                CR = insertBits(CR, 31 - bt, crBa == crBb);
            }});

            417: crorc({{
                uint32_t crBa = bits(CR, 31 - ba);
                uint32_t crBb = bits(CR, 31 - bb);
                CR = insertBits(CR, 31 - bt, crBa | !crBb);
            }});

            449: cror({{
                uint32_t crBa = bits(CR, 31 - ba);
                uint32_t crBb = bits(CR, 31 - bb);
                CR = insertBits(CR, 31 - bt, crBa | crBb);
            }});
        }

        // Conditionally branch to an address in a register based on
        // either CR only or both CR and CTR.
        format BranchRegCondOp {
            528: bcctr({{ NIA = CTR & -4ULL; }});
            560: bctar({{ NIA = TAR & -4ULL; }}, true);
        }

        default: decode DX_XO {
            2: IntDispArithOp::addpcis({{ Rt = NIA + (d << 16); }});
        }
    }

    format IntRotateOp {
        21: rlwinm({{
            uint64_t res;
            res = rotate(Rs, sh);
            res = res & bitmask(mb, me);
            Ra = res;
        }});

        23: rlwnm({{
            uint64_t res;
            res = rotate(Rs, Rb);
            res = res & bitmask(mb, me);
            Ra = res;
        }});

        20: rlwimi({{
            uint64_t res, mask;
            mask = bitmask(mb, me);
            res = rotate(Rs, sh);
            res = (res & mask) | (Ra & ~mask);
            Ra = res;
        }});
    }

    format IntImmLogicOp {
        24: ori({{ Ra = Rs | ui; }});
        25: oris({{ Ra = Rs | (ui << 16); }});
        26: xori({{ Ra = Rs ^ ui; }});
        27: xoris({{ Ra = Rs ^ (ui << 16); }});
        28: andi_({{ Ra = Rs & ui; }}, true);
        29: andis_({{ Ra = Rs & (ui << 16); }}, true);
    }

    // These instructions are of MD form and use bits 27 - 29 as XO.
    30: decode MD_XO {
        format IntConcatRotateOp {
            0: rldicl({{
                uint64_t res;
                if (sh != 0) {
                    res = rotate(Rs, sh);
                } else {
                    res = Rs;
                }
                res = res & bitmask(mb, 63);
                Ra = res;
            }});

            1: rldicr({{
                uint64_t res;
                if (sh != 0) {
                    res = rotate(Rs, sh);
                } else {
                    res = Rs;
                }
                res = res & bitmask(0, me);
                Ra = res;
            }});

            2: rldic({{
                uint64_t res;
                if (sh != 0) {
                    res = rotate(Rs, sh);
                } else {
                    res = Rs;
                }
                res = res & bitmask(mb, ~sh);
                Ra = res;
            }});

            3: rldimi({{
                uint64_t res, mask;
                mask = bitmask(mb, ~sh);
                if (sh != 0) {
                    res = rotate(Rs, sh);
                } else {
                    res = Rs;
                }
                res = res & mask;
                res = res | (Ra & ~mask);
                Ra = res;
            }});

            // These instructions are of MDS form and use bits 27 - 30 as XO.
            default: decode MDS_XO {
                8: rldcl({{
                    uint64_t res;
                    uint32_t shift = Rb & 0x3f;
                    if (shift != 0) {
                        res = rotate(Rs, shift);
                    } else {
                        res = Rs;
                    }
                    res = res & bitmask(mb, 63);
                    Ra = res;
                }});

                9: rldcr({{
                    uint64_t res;
                    uint32_t shift = Rb & 0x3f;
                    if (shift != 0) {
                        res = rotate(Rs, shift);
                    } else {
                        res = Rs;
                    }
                    res = res & bitmask(0, me);
                    Ra = res;
                }});
            }
        }
    }

    // There are a large number of instructions that have the same primary
    // opcode (PO) of 31. In this case, the instructions are of different
    // forms. For every form, the XO fields may vary in position and width.
    // The X, XFL, XFX and XL form instructions use bits 21 - 30 and the
    // XO form instructions use bits 22 - 30 as extended opcode (XO). To
    // avoid conflicts, instructions of each form have to be defined under
    // separate decode blocks. However, only a single decode block can be
    // associated with a particular PO and it will recognize only one type
    // of XO field. A solution for associating decode blocks for the other
    // types of XO fields with the same PO is to have the other blocks as
    // nested default cases.
    31: decode X_XO {

        0: IntCompOp::cmp({{
            if (l)
                cr = makeCRFieldSigned(Ra, Rb, xer.so);
            else
                cr = makeCRFieldSigned((int32_t)Ra, (int32_t)Rb, xer.so);
        }});

        4: IntTrapOp::tw({{ Ra_sw }}, {{ Rb_sw }});

        format LoadIndexOp {
            20: lwarx({{ Rt = Mem_uw; }},
                      {{ Rsv = 1; RsvLen = 4; RsvAddr = EA; }});

            21: ldx({{ Rt = Mem; }});
            23: lwzx({{ Rt = Mem_uw; }});
        }

        24: IntShiftOp::slw({{
            int32_t shift = Rb_sw;
            uint32_t res = Rs_uw & ~((shift << 26) >> 31);
            if (shift != 0) {
                shift = bits(shift, 4, 0);
                res = res << shift;
            }
            Ra = res;
        }});

        26: IntLogicOp::cntlzw({{ Ra = findLeadingZeros(Rs_uw); }}, true);

        27: IntConcatShiftOp::sld({{
            int64_t shift = Rb_sd;
            uint64_t res = Rs & ~((shift << 57) >> 63);
            if (shift != 0) {
                shift = bits(shift, 5, 0);
                res = res << shift;
            }
            Ra = res;
        }});

        28: IntLogicOp::and({{ Ra = Rs & Rb; }}, true);

        32: IntCompOp::cmpl({{
            if (l)
                cr = makeCRFieldUnsigned(Ra, Rb, xer.so);
            else
                cr = makeCRFieldUnsigned((uint32_t)Ra, (uint32_t)Rb, xer.so);
        }});

        52: LoadIndexOp::lbarx({{ Rt = Mem_ub; }},
                               {{ Rsv = 1; RsvLen = 1; RsvAddr = EA; }});

        53: LoadIndexUpdateOp::ldux({{ Rt = Mem; }});
        55: LoadIndexUpdateOp::lwzux({{ Rt = Mem_uw; }});

        format IntLogicOp {
            58: cntlzd({{ Ra = findLeadingZeros(Rs); }}, true);
            60: andc({{ Ra = Rs & ~Rb; }}, true);
        }

        68: IntTrapOp::td({{ Ra }}, {{ Rb }});

        format LoadIndexOp {
            84: ldarx({{ Rt = Mem_ud; }},
                      {{ Rsv = 1; RsvLen = 8; RsvAddr = EA; }});

            87: lbzx({{ Rt = Mem_ub; }});

            116: lharx({{ Rt = Mem_uh;}},
                       {{  Rsv = 1; RsvLen = 2; RsvAddr = EA; }});
        }

        119: LoadIndexUpdateOp::lbzux({{ Rt = Mem_ub; }});

        format IntLogicOp {
            122: popcntb({{
                // Based on "Counting bits set, in parallel"
                // from https://graphics.stanford.edu/~seander/bithacks.html
                const uint64_t m1 = 0x5555555555555555ULL;
                const uint64_t m2 = 0x3333333333333333ULL;
                const uint64_t m4 = 0x0f0f0f0f0f0f0f0fULL;
                uint64_t res = Rs;
                res = (res & m1) + ((res >> 1) & m1);
                res = (res & m2) + ((res >> 2) & m2);
                res = (res & m4) + ((res >> 4) & m4);
                Ra = res;
            }});

            124: nor({{ Ra = ~(Rs | Rb); }}, true);
        }

        format StoreIndexOp {
            149: stdx({{ Mem = Rs }});
            150: stwcx({{
                Mem_uw = Rs_uw;
            }}, {{
                bool store_performed = false;
                if (Rsv) {
                    if (RsvLen == 4) {
                        if (RsvAddr == EA) {
                            store_performed = true;
                        }
                    }
                }
                Xer xer = XER;
                PowerISA::Cr cr = CR;
                cr.cr0 = ((store_performed ? 0x2 : 0x0) | xer.so);
                CR = cr;
                Rsv = 0;
            }});

            151: stwx({{ Mem_uw = Rs_uw; }});
        }

        154: IntLogicOp::prtyw({{
            uint64_t res = Rs;
            res = res ^ (res >> 16);
            res = res ^ (res >> 8);
            res = res & 0x100000001;
            Ra = res;
        }});

        format StoreIndexUpdateOp {
            181: stdux({{ Mem = Rs; }});
            183: stwux({{ Mem_uw = Rs_uw; }});
        }

        186: IntLogicOp::prtyd({{
            uint64_t res = Rs;
            res = res ^ (res >> 32);
            res = res ^ (res >> 16);
            res = res ^ (res >> 8);
            res = res & 0x1;
            Ra = res;
        }});

        192: IntCompOp::cmprb({{
            uint32_t src1 = Ra_ub;
            uint32_t src2 = Rb_uw;
            uint8_t src2lo = src2 & 0xff;
            uint8_t src2hi = (src2 >>= 8) & 0xff;
            uint32_t res = (src2lo <= src1) & (src1 <= src2hi);
            if (l) {
                src2lo = (src2 >>= 8) & 0xff;
                src2hi = (src2 >>= 8) & 0xff;
                res = ((src2lo <= src1) & (src1 <= src2hi)) | res;
            }
            cr = res << 2;
        }});

        format StoreIndexOp {
            214: stdcx({{
                Mem = Rs;
            }}, {{
                bool store_performed = false;
                if (Rsv) {
                    if (RsvLen == 8) {
                        if (RsvAddr == EA) {
                            store_performed = true;
                        }
                    }
                }
                Xer xer = XER;
                Cr cr = CR;
                cr.cr0 = ((store_performed ? 0x2 : 0x0) | xer.so);
                CR = cr;
                Rsv = 0;
            }});

            215: stbx({{ Mem_ub = Rs_ub; }});
        }

        224: IntCompOp::cmpeqb({{
            // Based on "Determine if a word has a byte equal to n"
            // from https://graphics.stanford.edu/~seander/bithacks.html
            const uint64_t m1 = 0x0101010101010101;
            const uint64_t m2 = 0x8080808080808080;
            uint64_t res = Rb ^ (Ra_ub * m1);
            res = (res - m1) & ~res & m2;
            cr = (res != 0) << 2;
        }});

        246: MiscOp::dcbtst({{ }});
        247: StoreIndexUpdateOp::stbux({{ Mem_ub = Rs_ub; }});

        252: IntLogicOp::bpermd({{
            uint64_t res = 0;
            for (int i = 0; i < 8; ++i) {
                int index = (Rs >> (i * 8)) & 0xff;
                if ((index < 64) && bits(Rb, 63 - index)) {
                        res |= 1 << i;
                }
            }
            Ra = res;
        }});

        format IntArithOp {
            265: modud({{
                uint64_t src1 = Ra;
                uint64_t src2 = Rb;
                if (src2 != 0) {
                    Rt = src1 % src2;
                } else {
                    Rt = 0;
                }
            }});

            267: moduw({{
                uint64_t src1 = Ra_uw;
                uint64_t src2 = Rb_uw;
                if (src2 != 0) {
                    Rt = src1 % src2;
                } else {
                    Rt = 0;
                }
            }});
        }

        278: MiscOp::dcbt({{ }});
        279: LoadIndexOp::lhzx({{ Rt = Mem_uh; }});
        284: IntLogicOp::eqv({{ Ra = ~(Rs ^ Rb); }}, true);
        311: LoadIndexUpdateOp::lhzux({{ Rt = Mem_uh; }});
        316: IntLogicOp::xor({{ Ra = Rs ^ Rb; }}, true);

        format LoadIndexOp {
            341: lwax({{ Rt = Mem_sw; }});
            343: lhax({{ Rt = Mem_sh; }});
        }

        format LoadIndexUpdateOp {
            373: lwaux({{ Rt = Mem_sw; }});
            375: lhaux({{ Rt = Mem_sh; }});
        }

        378: IntLogicOp::popcntw({{
        #if defined(__GNUC__) || (defined(__clang__) && \
                __has_builtin(__builtin_popcount))
            uint64_t src = Rs;
            uint64_t res = __builtin_popcount(src >> 32);
            res = (res << 32) | __builtin_popcount(src);
        #else
            // Based on "Counting bits set, in parallel"
            // from https://graphics.stanford.edu/~seander/bithacks.html
            const uint64_t m1 = 0x5555555555555555ULL;
            const uint64_t m2 = 0x3333333333333333ULL;
            const uint64_t m4 = 0x0f0f0f0f0f0f0f0fULL;
            const uint64_t m8 = 0x00ff00ff00ff00ffULL;
            const uint64_t m16 = 0x0000ffff0000ffffULL;
            uint64_t res = Rs;
            res = (res & m1) + ((res >> 1) & m1);
            res = (res & m2) + ((res >> 2) & m2);
            res = (res & m4) + ((res >> 4) & m4);
            res = (res & m8) + ((res >> 8) & m8);
            res = (res & m16) + ((res >> 16) & m16);
        #endif
            Ra = res;
        }});

        407: StoreIndexOp::sthx({{ Mem_uh = Rs_uh; }});
        412: IntLogicOp::orc({{ Ra = Rs | ~Rb; }}, true);
        439: StoreIndexUpdateOp::sthux({{ Mem_uh = Rs_uh; }});

        format IntLogicOp {
            444: or({{ Ra = Rs | Rb; }}, true);
            476: nand({{ Ra = ~(Rs & Rb); }}, true);
            506: popcntd({{ Ra = popCount(Rs); }});

            508: cmpb({{
                uint64_t mask = 0xff;
                uint64_t res = 0;
                for (int i = 0; i < 8; ++i) {
                    if ((Rs & mask) == (Rb & mask)) {
                        res |= mask;
                    }
                    mask <<= 8;
                }
                Ra = res;
            }});
        }

        format LoadIndexOp {
            532: ldbrx({{ Rt = swap_byte(Mem); }});
            534: lwbrx({{ Rt = swap_byte(Mem_uw); }});
            535: lfsx({{ Ft_sf = Mem_sf; }});
        }

        536: IntShiftOp::srw({{
            int32_t shift = Rb_sw;
            uint32_t res = Rs_uw & ~((shift << 26) >> 31);
            if (shift != 0) {
                shift = bits(shift, 4, 0);
                res = res >> shift;
            }
            Ra = res;
        }});

        538: IntLogicOp::cnttzw({{ Ra = findTrailingZeros(Rs_uw); }}, true);

        539: IntConcatShiftOp::srd({{
            int64_t shift = Rb_sd;
            uint64_t res = Rs & ~((shift << 57) >> 63);
            if (shift != 0) {
                shift = bits(shift, 5, 0);
                res = res >> shift;
            }
            Ra = res;
        }});

        567: LoadIndexUpdateOp::lfsux({{ Ft_sf = Mem_sf; }});
        570: IntLogicOp::cnttzd({{ Ra = findTrailingZeros(Rs); }}, true);

        576: IntOp::mcrxrx({{
            uint8_t res;
            Xer xer = XER;
            res = (xer.ov << 3) | (xer.ov32 << 2) | (xer.ca << 1) | xer.ca32;
            CR = insertCRField(CR, BF, res);
        }});

        598: MiscOp::sync({{ }}, [ IsReadBarrier, IsWriteBarrier ]);
        599: LoadIndexOp::lfdx({{ Ft = Mem_df; }});
        631: LoadIndexUpdateOp::lfdux({{ Ft = Mem_df; }});

        format StoreIndexOp {
            660: stdbrx({{ Mem = swap_byte(Rs); }});
            662: stwbrx({{ Mem_uw = swap_byte(Rs_uw); }});
            663: stfsx({{ Mem_sf = Fs_sf; }});

            694: stbcx({{
                Mem_ub = Rs_ub;
            }}, {{
                bool store_performed = false;
                if (Rsv) {
                    if (RsvLen == 1) {
                        if (RsvAddr == EA) {
                            store_performed = true;
                        }
                    }
                }
                Xer xer = XER;
                Cr cr = CR;
                cr.cr0 = ((store_performed ? 0x2 : 0x0) | xer.so);
                CR = cr;
                Rsv = 0;
            }});
        }

        695: StoreIndexUpdateOp::stfsux({{ Mem_sf = Fs_sf; }});

        format StoreIndexOp {
            726: sthcx({{
                Mem_uh = Rs_uh;
            }}, {{
                bool store_performed = false;
                if (Rsv) {
                    if (RsvLen == 2) {
                        if (RsvAddr == EA) {
                            store_performed = true;
                        }
                    }
                }
                Xer xer = XER;
                Cr cr = CR;
                cr.cr0 = ((store_performed ? 0x2 : 0x0) | xer.so);
                CR = cr;
                Rsv = 0;
            }});

            727: stfdx({{ Mem_df = Fs; }});
        }

        759: StoreIndexUpdateOp::stfdux({{ Mem_df = Fs; }});

        format IntArithOp {
            777: modsd({{
                int64_t src1 = Ra_sd;
                int64_t src2 = Rb_sd;
                if ((src1 != INT64_MIN || src2 != -1) && src2 != 0) {
                    Rt = src1 % src2;
                } else {
                    Rt = 0;
                }
            }});

            779: modsw({{
                int64_t src1 = Ra_sw;
                int64_t src2 = Rb_sw;
                if ((src1 != INT32_MIN || src2 != -1) && src2 != 0) {
                    Rt = src1 % src2;
                } else {
                    Rt = 0;
                }
            }});
        }

        790: LoadIndexOp::lhbrx({{ Rt = swap_byte(Mem_uh); }});

        792: IntShiftOp::sraw({{
            int32_t src = Rs_sw;
            uint32_t shift = Rb_uw;
            int64_t res;
            if (bits(shift, 5)) {
                res = src >> 31;
                if (res != 0) {
                    setCA = true;
                }
            } else {
                if (shift != 0) {
                    shift = bits(shift, 4, 0);
                    res = src >> shift;
                    setCA = src < 0 && (src & mask(shift)) != 0;
                } else {
                    res = src;
                }
            }
            Ra = res;
        }}, true);

        794: IntConcatShiftOp::srad({{
            int64_t src = Rs_sd;
            uint64_t shift = Rb;
            int64_t res;
            if (bits(shift, 6)) {
                res = src >> 63;
                setCA = res != 0;
            } else {
                if (shift != 0) {
                    shift = shift & 0x3f;
                    res = src >> shift;
                    setCA = src < 0 && (src & mask(shift)) != 0;
                } else {
                    res = src;
                }
            }
            Ra = res;
        }}, true);

        824: IntShiftOp::srawi({{
            int32_t src = Rs_sw;
            int64_t res;
            if (sh) {
                res = src >> sh;
                setCA = src < 0 && (src & mask(sh)) != 0;
            } else {
                res = src;
            }
            Ra = res;
        }}, true);

        854: MiscOp::eieio({{ }}, [ IsReadBarrier, IsWriteBarrier ]);
        855: LoadIndexOp::lfiwax({{ Ft_uw = Mem; }});
        918: StoreIndexOp::sthbrx({{ Mem_uh = swap_byte(Rs_uh); }});

        format IntLogicOp {
            922: extsh({{ Ra = sext<16>(Rs); }}, true);
            954: extsb({{ Ra = sext<8>(Rs); }}, true);
        }

        983: StoreIndexOp::stfiwx({{ Mem = Fs_uw; }});
        986: IntLogicOp::extsw({{ Ra = sext<32>(Rs); }}, true);

        // These instructions are of XO form with bit 21 as the OE bit.
        default: decode XO_XO {
            8: IntSumOp::subfc({{ ~Ra }}, {{ Rb }}, {{ 1 }}, true);

            9: IntArithCheckRcOp::mulhdu({{
                uint64_t res;
                std::tie(std::ignore, res) = multiply(Ra, Rb);
                Rt = res;
            }});

            10: IntSumOp::addc({{ Ra }}, {{ Rb }}, computeCA = true);

            11: IntArithCheckRcOp::mulhwu({{
                uint64_t res = (uint64_t)Ra_uw * Rb_uw;
                res = res >> 32;
                Rt = res;
            }});

            40: IntSumOp::subf({{ ~Ra }}, {{ Rb }}, {{ 1 }});

            format IntArithCheckRcOp {
                73: mulhd({{
                    int64_t res;
                    std::tie(std::ignore, res) = multiply(Ra_sd, Rb_sd);
                    Rt = res;
                }});

                75: mulhw({{
                    uint64_t res = (int64_t)Ra_sw * Rb_sw;
                    res = res >> 32;
                    Rt = res;
                }});
            }

            format IntSumOp {
                104: neg({{ ~Ra }}, {{ 1 }});
                136: subfe({{ ~Ra }}, {{ Rb }}, {{ xer.ca }}, true);
                138: adde({{ Ra }}, {{ Rb }}, {{ xer.ca }}, true);
                200: subfze({{ ~Ra }}, {{ xer.ca }}, computeCA = true);
                202: addze({{ Ra }}, {{ xer.ca }}, computeCA = true);
                232: subfme({{ ~Ra }}, {{ -1ULL }}, {{ xer.ca }}, true);
                234: addme({{ Ra }}, {{ -1ULL }}, {{ xer.ca }}, true);
            }

            format IntArithCheckRcOp {
                233: mulld({{
                    int64_t src1 = Ra_sd;
                    int64_t src2 = Rb_sd;
                    uint64_t res = src1 * src2;
                    std::tie(res, std::ignore) = multiply(src1, src2);
                    if (src1 != 0 && (int64_t)res / src1 != src2) {
                        setOV = true;
                    }
                    Rt = res;
                }}, true);

                235: mullw({{
                    int64_t res = (int64_t)Ra_sw * Rb_sw;
                    if (res != (int32_t)res) {
                        setOV = true;
                    }
                    Rt = res;
                }}, true);
            }

            266: IntSumOp::add({{ Ra }}, {{ Rb }});

            format IntArithCheckRcOp {
                393: divdeu({{
                    uint64_t src1 = Ra;
                    uint64_t src2 = Rb;
                    uint64_t res;
                    std::tie(setOV, res, std::ignore) = divide(0, src1, src2);
                    if (!setOV) {
                        Rt = res;
                    } else {
                        Rt = 0;
                    }
                }}, true);

                395: divweu({{
                    uint32_t src1 = Ra_ud;
                    uint32_t src2 = Rb_ud;
                    uint64_t res;
                    if (src2 != 0) {
                        res = ((uint64_t)src1 << 32) / src2;
                        if (res <= UINT32_MAX) {
                            Rt = (uint32_t)res;
                        } else {
                            Rt = 0;
                            setOV = true;
                        }
                    } else {
                        Rt = 0;
                        setOV = true;
                    }
                }}, true);

                425: divde({{
                    int64_t src1 = Ra_sd;
                    int64_t src2 = Rb_sd;
                    int64_t res;
                    std::tie(setOV, res, std::ignore) = divide(0, src1, src2);
                    if (!setOV) {
                        Rt = res;
                    } else {
                        Rt = 0;
                    }
                }}, true);

                427: divwe({{
                    int32_t src1 = Ra_sw;
                    int32_t src2 = Rb_sw;
                    int64_t res;
                    if ((src1 != INT32_MIN || src2 != -1) && src2 != 0) {
                        res = ((int64_t)src1 << 32) / src2;
                        if (res == (int32_t)res) {
                            Rt = (uint32_t)res;
                        } else {
                            Rt = 0;
                            setOV = true;
                        }
                    } else {
                        Rt = 0;
                        setOV = true;
                    }
                }}, true);

                457: divdu({{
                    uint64_t src1 = Ra;
                    uint64_t src2 = Rb;
                    if (src2 != 0) {
                        Rt = src1 / src2;
                    } else {
                        Rt = 0;
                        setOV = true;
                    }
                }}, true);

                459: divwu({{
                    uint32_t src1 = Ra_uw;
                    uint32_t src2 = Rb_uw;
                    if (src2 != 0) {
                        Rt = src1 / src2;
                    } else {
                        Rt = 0;
                        setOV = true;
                    }
                }}, true);

                489: divd({{
                    int64_t src1 = Ra_sd;
                    int64_t src2 = Rb_sd;
                    if ((src1 != INT64_MIN || src2 != -1) && src2 != 0) {
                        Rt = src1 / src2;
                    } else {
                        Rt = 0;
                        setOV = true;
                    }
                }}, true);

                491: divw({{
                    int32_t src1 = Ra_sw;
                    int32_t src2 = Rb_sw;
                    if ((src1 != INT32_MIN || src2 != -1) && src2 != 0) {
                        Rt = (uint32_t)(src1 / src2);
                    } else {
                        Rt = 0;
                        setOV = true;
                    }
                }}, true);
            }

            // These instructions are of XS form and use bits 21 - 29 as XO.
            default: decode XS_XO {
                format IntConcatShiftOp {
                    413: sradi({{
                        int64_t src = Rs_sd;
                        if (sh != 0) {
                            Ra = src >> sh;
                            if (src < 0 && (src & mask(sh))) {
                                setCA = true;
                            }
                        } else {
                            Ra = src;
                        }
                    }}, true);

                    445: extswsli({{
                        int64_t src = Rs_sw;
                        if (sh != 0) {
                            Ra = src << sh;
                        } else {
                            Ra = src;
                        }
                    }});
                }

                default: decode XFX_XO {
                    format IntOp {
                        19: decode S {
                            0: mfcr({{ Rt = CR; }});

                            1: mfocrf({{
                                int count = popCount(FXM);
                                uint64_t mask = 0xf << (4 * findMsbSet(FXM));
                                if (count == 1) {
                                    Rt = CR & mask;
                                }
                            }});
                        }

                        144: decode S {
                            0: mtcrf({{
                                uint32_t mask = 0;
                                for (int i = 0; i < 8; ++i) {
                                    if (bits(FXM, i)) {
                                        mask |= 0xf << (4 * i);
                                    }
                                }
                                CR = (Rs & mask) | (CR & ~mask);
                            }});

                            1: mtocrf({{
                                int count = popCount(FXM);
                                uint32_t mask = 0xf << (4 * findMsbSet(FXM));
                                if (count == 1) {
                                    CR = (Rs & mask) | (CR & ~mask);
                                }
                            }});
                        }

                        339: decode SPR {
                            0x20: mfxer({{ Rt = XER; }});
                            0x100: mflr({{ Rt = LR; }});
                            0x120: mfctr({{ Rt = CTR; }});
                            0x1f9: mftar({{ Rt = TAR; }});
                            0x188: mftb({{ Rt = curTick(); }});
                            0x1a8: mftbu({{ Rt_uw = curTick() >> 32; }});
                        }

                        467: decode SPR {
                            0x20: mtxer({{ XER = Rs; }});
                            0x100: mtlr({{ LR = Rs; }});
                            0x120: mtctr({{ CTR = Rs; }});
                            0x1f9: mttar({{ TAR = Rs; }});
                        }

                        512: mcrxr({{
                            CR = insertCRField(CR, BF, XER<31:28>);
                            XER = XER<27:0>;
                        }});
                    }
                }
            }
        }
    }

    32: LoadDispOp::lwz({{ Rt = Mem_uw; }});
    33: LoadDispUpdateOp::lwzu({{ Rt = Mem_uw; }});
    34: LoadDispOp::lbz({{ Rt = Mem_ub; }});
    35: LoadDispUpdateOp::lbzu({{ Rt = Mem_ub; }});
    36: StoreDispOp::stw({{ Mem_uw = Rs_uw; }});
    37: StoreDispUpdateOp::stwu({{ Mem_uw = Rs_uw; }});
    38: StoreDispOp::stb({{ Mem_ub = Rs_ub; }});
    39: StoreDispUpdateOp::stbu({{ Mem_ub = Rs_ub; }});
    40: LoadDispOp::lhz({{ Rt = Mem_uh; }});
    41: LoadDispUpdateOp::lhzu({{ Rt = Mem_uh; }});
    42: LoadDispOp::lha({{ Rt = Mem_sh; }});
    43: LoadDispUpdateOp::lhau({{ Rt = Mem_sh; }});
    44: StoreDispOp::sth({{ Mem_uh = Rs_uh; }});
    45: StoreDispUpdateOp::sthu({{ Mem_uh = Rs_uh; }});
    48: LoadDispOp::lfs({{ Ft_sf = Mem_sf; }});
    49: LoadDispUpdateOp::lfsu({{ Ft_sf = Mem_sf; }});
    50: LoadDispOp::lfd({{ Ft = Mem_df; }});
    51: LoadDispUpdateOp::lfdu({{ Ft = Mem_df; }});
    52: StoreDispOp::stfs({{ Mem_sf = Fs_sf; }});
    53: StoreDispUpdateOp::stfsu({{ Mem_sf = Fs_sf; }});
    54: StoreDispOp::stfd({{ Mem_df = Fs; }});
    55: StoreDispUpdateOp::stfdu({{ Mem_df = Fs; }});

    58: decode DS_XO {
        0: LoadDispShiftOp::ld({{ Rt = Mem; }});
        1: LoadDispShiftUpdateOp::ldu({{ Rt = Mem; }});
        2: LoadDispShiftOp::lwa({{ Rt = Mem_sw; }});
    }

    format FloatArithOp {
        59: decode A_XO {
            18: fdivs({{ Ft = Fa / Fb; }});
            20: fsubs({{ Ft = Fa - Fb; }});
            21: fadds({{ Ft = Fa + Fb; }});
            25: fmuls({{ Ft = Fa * Fc; }});
            28: fmsubs({{ Ft = (Fa * Fc) - Fb; }});
            29: fmadds({{ Ft = (Fa * Fc) + Fb; }});
            30: fnmsubs({{ Ft = -((Fa * Fc) - Fb); }});
            31: fnmadds({{ Ft = -((Fa * Fc) + Fb); }});
        }
    }

    62: decode DS_XO {
        0: StoreDispShiftOp::std({{ Mem = Rs; }});
        1: StoreDispShiftUpdateOp::stdu({{ Mem = Rs; }});
    }

    63: decode A_XO {
        format FloatArithOp {
            20: fsub({{ Ft = Fa - Fb; }});
            21: fadd({{ Ft = Fa + Fb; }});
            25: fmul({{ Ft = Fa * Fc; }});
            18: fdiv({{ Ft = Fa / Fb; }});
            29: fmadd({{ Ft = (Fa * Fc) + Fb; }});
            28: fmsub({{ Ft = (Fa * Fc) - Fb; }});
            31: fnmadd({{ Ft = -((Fa * Fc) + Fb); }});
            30: fnmsub({{ Ft = -((Fa * Fc) - Fb); }});
        }

        default: decode X_XO {
            0: FloatOp::fcmpu({{
                uint32_t c = makeCRField(Fa, Fb);
                Fpscr fpscr = FPSCR;
                fpscr.fprf.fpcc = c;
                FPSCR = fpscr;
                CR = insertCRField(CR, BF, c);
            }});

            8: FloatRCCheckOp::fcpsgn({{
                Ft_ud = Fb_ud;
                Ft_ud = insertBits(Ft_ud, 63, Fa_ud<63:63>);
            }});

            format FloatConvertOp {
                12: frsp({{ Ft_sf = Fb; }});
                15: fctiwz({{ Ft_sw = (int32_t)trunc(Fb); }});
            }

            format FloatRCCheckOp {
                38: mtfsb1({{ FPSCR = insertBits(FPSCR, 31 - BT, 1); }});
                40: fneg({{ Ft = -Fb; }});
                70: mtfsb0({{ FPSCR = insertBits(FPSCR, 31 - BT, 0); }});
                72: fmr({{ Ft = Fb; }});

                134: mtfsfi({{
                    FPSCR = insertCRField(FPSCR, BF + (8 * (1 - W_FIELD)),
                                          U_FIELD);
                }});

                136: fnabs({{
                    Ft_ud = Fb_ud;
                    Ft_ud = insertBits(Ft_ud, 63, 1);
                }});

                264: fabs({{
                    Ft_ud = Fb_ud;
                    Ft_ud = insertBits(Ft_ud, 63, 0);
                }});

                583: mffs({{ Ft_ud = FPSCR; }});

                default: decode XFL_XO {
                    711: mtfsf({{
                        if (L_FIELD == 1) { FPSCR = Fb_ud; }
                        else {
                            for (int i = 0; i < 8; ++i) {
                                if (bits(FLM, i) == 1) {
                                    int k = 4 * (i + (8 * (1 - W_FIELD)));
                                    FPSCR = insertBits(FPSCR, k + 3, k,
                                                       bits(Fb_ud, k + 3, k));
                                }
                            }
                        }
                    }});
                }
            }
        }
    }
}
